﻿using AdminPlugin;
using EleCho.GoCqHttpSdk;
using EleCho.GoCqHttpSdk.Post;
using ManualPlugin;
using MausBot;
using Microsoft.Extensions.Logging;
using PluginSdk;
using System.Collections.Concurrent;
using System.Reflection;
using System.Text.Json;
using System.Text.RegularExpressions;
using System.Threading.Channels;

using ILoggerFactory loggerFactory =
    LoggerFactory.Create(builder =>
        builder.AddSimpleConsole(options =>
        {
            options.IncludeScopes = true;
            options.SingleLine = true;
            options.TimestampFormat = "HH:mm:ss ";
        }));

Console.WriteLine("MausBot by df1050");

var config = (Config)JsonSerializer.Deserialize(File.ReadAllText("config.json"), typeof(Config));

var logger = loggerFactory.CreateLogger("MausBot");
logger.LogInformation("日志模块已启动");
logger.LogInformation("初始化连接......");
CqWsSession session = new CqWsSession(new CqWsSessionOptions()
{
    BaseUri = config.Uri,  // WebSocket 地址
});
session.Start();
logger.LogInformation("连接成功");
logger.LogInformation("加载插件......");

var Manuals = new ConcurrentDictionary<string, string>();
var TextCommands = new List<ITextCommand>();
var Commands1 = new List<ICommand<CqPostContext>>();
var Commands2 = new List<ICommand<CqClientStatusChangedPostContext>>();
var Commands3 = new List<ICommand<CqFriendAddedPostContext>>();
var Commands4 = new List<ICommand<CqFriendMessageRecalledPostContext>>();
var Commands5 = new List<ICommand<CqFriendRequestPostContext>>();
var Commands6 = new List<ICommand<CqGroupAdministratorChangedPostContext>>();
var Commands7 = new List<ICommand<CqGroupEssenceChangedPostContext>>();
var Commands8 = new List<ICommand<CqGroupFileUploadedPostContext>>();
var Commands9 = new List<ICommand<CqGroupLuckyKingNoticedPostContext>>();
var Commands10 = new List<ICommand<CqGroupMemberBanChangedPostContext>>();
var Commands11 = new List<ICommand<CqGroupMemberDecreasedPostContext>>();
var Commands12 = new List<ICommand<CqGroupMemberHonorChangedPostContext>>();
var Commands13 = new List<ICommand<CqGroupMemberIncreasedPostContext>>();
var Commands14 = new List<ICommand<CqGroupMemberNicknameChangedPostContext>>();
var Commands15 = new List<ICommand<CqGroupMemberTitleChangeNoticedPostContext>>();
var Commands16 = new List<ICommand<CqGroupMessagePostContext>>();
var Commands17 = new List<ICommand<CqGroupMessageRecalledPostContext>>();
var Commands18 = new List<ICommand<CqGroupRequestPostContext>>();
var Commands19 = new List<ICommand<CqGroupSelfMessagePostContext>>();
var Commands20 = new List<ICommand<CqHeartbeatPostContext>>();
var Commands21 = new List<ICommand<CqMessagePostContext>>();
var Commands22 = new List<ICommand<CqMetaEventPostContext>>();
var Commands23 = new List<ICommand<CqNoticePostContext>>();
var Commands24 = new List<ICommand<CqNotifyNoticePostContext>>();
var Commands25 = new List<ICommand<CqOfflineFileUploadedPostContext>>();
var Commands26 = new List<ICommand<CqPokedPostContext>>();
var Commands27 = new List<ICommand<CqPrivateMessagePostContext>>();
var Commands28 = new List<ICommand<CqPrivateSelfMessagePostContext>>();
var Commands29 = new List<ICommand<CqRequestPostContext>>();
var Commands30 = new List<ICommand<CqSelfMessagePostContext>>();
var MessageStreams = new List<MessageStream>();

var adminPlugin = new Admin(config.Masters, () =>
{
    File.WriteAllText("config.json", JsonSerializer.Serialize(config));
});
var manuals = new ConcurrentDictionary<string, string>();
var manualPlugin = new Manual(manuals);

var plugins = new List<IPlugin>() { adminPlugin, manualPlugin };
var folder = new DirectoryInfo($"{Environment.CurrentDirectory}/plugins/");
foreach (var i in folder.GetDirectories())
{
    foreach (var j in i.GetFiles())
    {
        if (Regex.Match(j.Name, ".*.dll").Success)
        {
            Assembly asm;
            try
            {
                asm = Assembly.LoadFile(j.FullName);
            }
            catch (Exception e)
            {
                logger.LogWarning(e.ToString());
                continue;
            }
            foreach (var type in asm.GetTypes())
                if (type.IsPublic && type.GetInterface("IPlugin") != null)
                    plugins.Add((IPlugin)Activator.CreateInstance(type));
        }
    }
}
foreach (var i in folder.GetFiles())
{
    var asm = Assembly.Load($"{Environment.CurrentDirectory}{Path.DirectorySeparatorChar}plugins{Path.DirectorySeparatorChar}{i.Name}");
    foreach (var type in asm.GetTypes())
        if (type.IsPublic && type.GetInterface("IPlugin") != null)
            plugins.Add((IPlugin)Activator.CreateInstance(type));
}

foreach (var p in plugins)
{
    p.ConfigLogger(loggerFactory);
    p.ConfigSession(session);
    p.Config();
    manuals.TryAdd(p.Name, p.Description);
    logger.LogInformation($"插件{p.Name}已加载");
    foreach (var c in p.Commands)
    {
        manuals.TryAdd(c.Name, c.Description);
        logger.LogInformation($"指令{c.Name}已加载");
        if (c is ITextCommand textCommand)
            TextCommands.Add(textCommand);
        else if (c is ICommand<CqPostContext> command1)
            Commands1.Add(command1);
        else if (c is ICommand<CqClientStatusChangedPostContext> command2)
            Commands2.Add(command2);
        else if (c is ICommand<CqFriendAddedPostContext> command3)
            Commands3.Add(command3);
        else if (c is ICommand<CqFriendMessageRecalledPostContext> command4)
            Commands4.Add(command4);
        else if (c is ICommand<CqFriendRequestPostContext> command5)
            Commands5.Add(command5);
        else if (c is ICommand<CqGroupAdministratorChangedPostContext> command6)
            Commands6.Add(command6);
        else if (c is ICommand<CqGroupEssenceChangedPostContext> command7)
            Commands7.Add(command7);
        else if (c is ICommand<CqGroupFileUploadedPostContext> command8)
            Commands8.Add(command8);
        else if (c is ICommand<CqGroupLuckyKingNoticedPostContext> command9)
            Commands9.Add(command9);
        else if (c is ICommand<CqGroupMemberBanChangedPostContext> command10)
            Commands10.Add(command10);
        else if (c is ICommand<CqGroupMemberDecreasedPostContext> command11)
            Commands11.Add(command11);
        else if (c is ICommand<CqGroupMemberHonorChangedPostContext> command12)
            Commands12.Add(command12);
        else if (c is ICommand<CqGroupMemberIncreasedPostContext> command13)
            Commands13.Add(command13);
        else if (c is ICommand<CqGroupMemberNicknameChangedPostContext> command14)
            Commands14.Add(command14);
        else if (c is ICommand<CqGroupMemberTitleChangeNoticedPostContext> command15)
            Commands15.Add(command15);
        else if (c is ICommand<CqGroupMessagePostContext> command16)
            Commands16.Add(command16);
        else if (c is ICommand<CqGroupMessageRecalledPostContext> command17)
            Commands17.Add(command17);
        else if (c is ICommand<CqGroupRequestPostContext> command18)
            Commands18.Add(command18);
        else if (c is ICommand<CqGroupSelfMessagePostContext> command19)
            Commands19.Add(command19);
        else if (c is ICommand<CqHeartbeatPostContext> command20)
            Commands20.Add(command20);
        else if (c is ICommand<CqMessagePostContext> command21)
            Commands21.Add(command21);
        else if (c is ICommand<CqMetaEventPostContext> command22)
            Commands22.Add(command22);
        else if (c is ICommand<CqNoticePostContext> command23)
            Commands23.Add(command23);
        else if (c is ICommand<CqNotifyNoticePostContext> command24)
            Commands24.Add(command24);
        else if (c is ICommand<CqOfflineFileUploadedPostContext> command25)
            Commands25.Add(command25);
        else if (c is ICommand<CqPokedPostContext> command26)
            Commands26.Add(command26);
        else if (c is ICommand<CqPrivateMessagePostContext> command27)
            Commands27.Add(command27);
        else if (c is ICommand<CqPrivateSelfMessagePostContext> command28)
            Commands28.Add(command28);
        else if (c is ICommand<CqRequestPostContext> command29)
            Commands29.Add(command29);
        else if (c is ICommand<CqSelfMessagePostContext> command30)
            Commands30.Add(command30);
    }
}
session.PostPipeline.Use(async (context, next) =>
{
    _ = Task.Run(async () =>
    {
        MessageStreams.RemoveAll(msgs => msgs.Closed);
        logger.LogInformation($"收到消息：{context}");
        foreach (var i in Commands1)
        {
            await i.Handler(context);
            logger.LogInformation($"{i.Name}处理了{context}");
        }
        if (context is CqMessagePostContext context1)
        {
            foreach (var i in MessageStreams)
                if (context is not CqGroupMessagePostContext groupcontext || groupcontext.GroupId == i.Gid)
                    switch (i.Permission)
                    {
                        case Permission.Admin:
                        case Permission.SameUser:
                            if (context1.UserId == i.Uid)
                            {
                                logger.LogInformation($"发送到Channel：{context1}");
                                await i.FeedMessage(context1);
                            }
                            break;
                        case Permission.SameGroup:
                            logger.LogInformation($"发送到Channel：{context1}");
                            await i.FeedMessage(context1);
                            break;
                    }
            foreach (var i in TextCommands)
                if (context is CqGroupMessagePostContext context2)
                    switch (i.Permission)
                    {
                        case Permission.Admin:
                            if (config.Masters.Contains(context2.UserId) && Regex.Match(context2.Message.Text, i.Match).Success)
                            {
                                logger.LogInformation($"建立Channel：{context2}");
                                var stream = new MessageStream(Channel.CreateBounded<CqMessagePostContext>(2), async (message) =>
                                {
                                    await session.SendGroupMessageAsync(context2.GroupId, message);
                                }, i.Permission, context2.GroupId, context2.UserId);
                                MessageStreams.Add(stream);
                                await stream.FeedMessage(context2);
                                logger.LogInformation($"发送到Channel：{context2}");
                                await i.Handler(stream);
                                stream.Close();
                            }
                            break;
                        case Permission.SameUser:
                        case Permission.SameGroup:
                            if (!Regex.Match(context2.Message.Text, i.Match).Success)
                                break;
                            logger.LogInformation($"建立Channel：{context2}");
                            var stream2 = new MessageStream(Channel.CreateBounded<CqMessagePostContext>(2), async (message) =>
                            {
                                await session.SendGroupMessageAsync(context2.GroupId, message);
                            }, i.Permission, context2.GroupId, context2.UserId);
                            MessageStreams.Add(stream2);
                            await stream2.FeedMessage(context2);
                            logger.LogInformation($"发送到Channel：{context2}");
                            await i.Handler(stream2);
                            stream2.Close();
                            break;
                    }
                else if (context is CqPrivateMessagePostContext context3)
                {
                    switch (i.Permission)
                    {
                        case Permission.Admin:
                            if (config.Masters.Contains(context3.UserId))
                            {
                                logger.LogInformation($"建立Channel：{context3}");
                                var stream = new MessageStream(Channel.CreateBounded<CqMessagePostContext>(2), async (message) =>
                                {
                                    await session.SendPrivateMessageAsync(context3.UserId, message);
                                }, i.Permission, 0, context3.UserId);
                                MessageStreams.Add(stream);
                                await stream.FeedMessage(context3);
                                logger.LogInformation($"发送到Channel：{context3}");
                                await i.Handler(stream);
                            }
                            break;
                        case Permission.SameUser:
                        case Permission.SameGroup:
                            logger.LogInformation($"建立Channel：{context3}");
                            var stream2 = new MessageStream(Channel.CreateBounded<CqMessagePostContext>(2), async (message) =>
                            {
                                await session.SendPrivateMessageAsync(context3.UserId, message);
                            }, i.Permission, 0, context3.UserId);
                            MessageStreams.Add(stream2);
                            await stream2.FeedMessage(context3);
                            logger.LogInformation($"发送到Channel：{context3}");
                            await i.Handler(stream2);
                            break;
                    }
                }
        }
        if (context is CqClientStatusChangedPostContext context4)
            foreach (var i in Commands2)
            {
                await i.Handler(context4);
                logger.LogInformation($"{i.Name}处理了{context4}");
            }
        if (context is CqFriendAddedPostContext context5)
            foreach (var i in Commands3)
            {
                await i.Handler(context5);
                logger.LogInformation($"{i.Name}处理了{context5}");
            }
        if (context is CqFriendMessageRecalledPostContext context6)
            foreach (var i in Commands4)
            {
                await i.Handler(context6);
                logger.LogInformation($"{i.Name}处理了{context6}");
            }
        if (context is CqFriendRequestPostContext context7)
            foreach (var i in Commands5)
            {
                await i.Handler(context7);
                logger.LogInformation($"{i.Name}处理了{context7}");
            }
        if (context is CqGroupAdministratorChangedPostContext context8)
            foreach (var i in Commands6)
            {
                await i.Handler(context8);
                logger.LogInformation($"{i.Name}处理了{context8}");
            }
        if (context is CqGroupEssenceChangedPostContext context9)
            foreach (var i in Commands7)
            {
                await i.Handler(context9);
                logger.LogInformation($"{i.Name}处理了{context9}");
            }
        if (context is CqGroupFileUploadedPostContext context10)
            foreach (var i in Commands8)
            {
                await i.Handler(context10);
                logger.LogInformation($"{i.Name}处理了{context10}");
            }
        if (context is CqGroupLuckyKingNoticedPostContext context11)
            foreach (var i in Commands9)
            {
                await i.Handler(context11);
                logger.LogInformation($"{i.Name}处理了{context11}");
            }
        if (context is CqGroupMemberBanChangedPostContext context12)
            foreach (var i in Commands10)
            {
                await i.Handler(context12);
                logger.LogInformation($"{i.Name}处理了{context12}");
            }
        if (context is CqGroupMemberDecreasedPostContext context13)
            foreach (var i in Commands11)
            {
                await i.Handler(context13);
                logger.LogInformation($"{i.Name}处理了{context13}");
            }
        if (context is CqGroupMemberHonorChangedPostContext context14)
            foreach (var i in Commands12)
            {
                await i.Handler(context14);
                logger.LogInformation($"{i.Name}处理了{context14}");
            }
        if (context is CqGroupMemberIncreasedPostContext context15)
            foreach (var i in Commands13)
            {
                await i.Handler(context15);
                logger.LogInformation($"{i.Name}处理了{context15}");
            }
        if (context is CqGroupMemberNicknameChangedPostContext context16)
            foreach (var i in Commands14)
            {
                await i.Handler(context16);
                logger.LogInformation($"{i.Name}处理了{context16}");
            }
        if (context is CqGroupMemberTitleChangeNoticedPostContext context17)
            foreach (var i in Commands15)
            {
                await i.Handler(context17);
                logger.LogInformation($"{i.Name}处理了{context17}");
            }
        if (context is CqGroupMessagePostContext context18)
            foreach (var i in Commands16)
            {
                await i.Handler(context18);
                logger.LogInformation($"{i.Name}处理了{context18}");
            }
        if (context is CqGroupMessageRecalledPostContext context19)
            foreach (var i in Commands17)
            {
                await i.Handler(context19);
                logger.LogInformation($"{i.Name}处理了{context19}");
            }
        if (context is CqGroupRequestPostContext context20)
            foreach (var i in Commands18)
            {
                await i.Handler(context20);
                logger.LogInformation($"{i.Name}处理了{context20}");
            }
        if (context is CqGroupSelfMessagePostContext context21)
            foreach (var i in Commands19)
            {
                await i.Handler(context21);
                logger.LogInformation($"{i.Name}处理了{context21}");
            }
        if (context is CqHeartbeatPostContext context22)
            foreach (var i in Commands20)
            {
                await i.Handler(context22);
                logger.LogInformation($"{i.Name}处理了{context22}");
            }
        if (context is CqMessagePostContext context23)
            foreach (var i in Commands21)
            {
                await i.Handler(context23);
                logger.LogInformation($"{i.Name}处理了{context23}");
            }
        if (context is CqMetaEventPostContext context24)
            foreach (var i in Commands22)
            {
                await i.Handler(context24);
                logger.LogInformation($"{i.Name}处理了{context24}");
            }
        if (context is CqNoticePostContext context25)
            foreach (var i in Commands23)
            {
                await i.Handler(context25);
                logger.LogInformation($"{i.Name}处理了{context25}");
            }
        if (context is CqNotifyNoticePostContext context26)
            foreach (var i in Commands24)
            {
                await i.Handler(context26);
                logger.LogInformation($"{i.Name}处理了{context26}");
            }
        if (context is CqOfflineFileUploadedPostContext context27)
            foreach (var i in Commands25)
            {
                await i.Handler(context27);
                logger.LogInformation($"{i.Name}处理了{context27}");
            }
        if (context is CqPokedPostContext context28)
            foreach (var i in Commands26)
            {
                await i.Handler(context28);
                logger.LogInformation($"{i.Name}处理了{context28}");
            }
        if (context is CqPrivateMessagePostContext context29)
            foreach (var i in Commands27)
            {
                await i.Handler(context29);
                logger.LogInformation($"{i.Name}处理了{context29}");
            }
        if (context is CqPrivateSelfMessagePostContext context30)
            foreach (var i in Commands28)
            {
                await i.Handler(context30);
                logger.LogInformation($"{i.Name}处理了{context30}");
            }
        if (context is CqRequestPostContext context31)
            foreach (var i in Commands29)
            {
                await i.Handler(context31);
                logger.LogInformation($"{i.Name}处理了{context31}");
            }
        if (context is CqSelfMessagePostContext context32)
            foreach (var i in Commands30)
            {
                await i.Handler(context32);
                logger.LogInformation($"{i.Name}处理了{context32}");
            }
    });

    await next.Invoke();
});

await Task.Delay(-1);